#!/bin/bash

# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 无颜色

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_step() {
    echo -e "${BLUE}[STEP]${NC} $1"
}

# 检查是否为root用户
if [ "$(id -u)" != "0" ]; then
   log_error "此脚本必须以root权限运行" 
   exit 1
fi

# 设置环境变量
APP_DIR="/var/www/box-user"
BACKUP_DIR="/var/backups/box-user/$(date +%Y%m%d_%H%M%S)"
LOG_FILE="/var/log/box-user/deploy_$(date +%Y%m%d_%H%M%S).log"
DEPLOY_LOCK="/tmp/box_user_deploy.lock"

# 确保日志目录存在
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$BACKUP_DIR"

# 将所有输出重定向到日志文件
exec > >(tee -a "$LOG_FILE") 2>&1

# 显示脚本横幅
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "  妙趣拾光锦盒用户系统 - 自动化部署工具 v2.0"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# 检查部署锁，防止多个部署脚本同时运行
if [ -f "$DEPLOY_LOCK" ]; then
    LOCK_PID=$(cat "$DEPLOY_LOCK")
    if ps -p "$LOCK_PID" > /dev/null; then
        log_error "另一个部署进程 (PID: $LOCK_PID) 正在运行。如果确定没有其他部署进程在运行，请删除锁文件: $DEPLOY_LOCK"
        exit 1
    else
        log_warn "发现过时的部署锁，将继续执行"
        rm -f "$DEPLOY_LOCK"
    fi
fi

# 创建部署锁
echo $$ > "$DEPLOY_LOCK"

# 定义清理函数，确保脚本结束后删除锁文件
cleanup() {
    rm -f "$DEPLOY_LOCK"
    log_info "部署完成，锁文件已删除"
}

# 捕获退出信号，确保锁文件被删除
trap cleanup EXIT

log_step "开始自动化部署流程..."
log_info "应用目录: $APP_DIR"
log_info "备份目录: $BACKUP_DIR"
log_info "日志文件: $LOG_FILE"
log_info "部署时间: $(date)"

# 检查应用目录是否存在
if [ ! -d "$APP_DIR" ]; then
    log_error "应用目录 $APP_DIR 不存在！请先运行初始部署脚本。"
    exit 1
fi

# 创建数据库备份
log_step "创建数据库备份..."
if [ -f "$APP_DIR/scripts/backup_db.py" ]; then
    cd "$APP_DIR"
    source venv/bin/activate
    python scripts/backup_db.py
    
    if [ $? -eq 0 ]; then
        log_info "数据库备份成功"
    else
        log_warn "数据库备份失败，但将继续部署过程"
    fi
    deactivate
else
    log_warn "数据库备份脚本不存在，跳过数据库备份"
fi

# 创建文件备份
log_step "创建应用文件备份..."
rsync -a --exclude="venv" --exclude=".git" "$APP_DIR/" "$BACKUP_DIR/"
log_info "备份已保存到: $BACKUP_DIR"

# 进入应用目录
cd "$APP_DIR" || {
    log_error "无法进入应用目录！"
    exit 1
}

# 获取部署前的Git版本
OLD_VERSION=$(git describe --always --tags 2>/dev/null || echo 'Unknown')
log_info "当前版本: $OLD_VERSION"

# 检查是否是Git仓库
if [ ! -d ".git" ]; then
    log_warn "目录不是Git仓库，跳过代码更新步骤"
else
    # 保存当前分支名
    CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
    log_info "当前分支: $CURRENT_BRANCH"

    # 提示用户选择更新方式
    echo ""
    echo "选择更新方式:"
    echo "  [1] 从当前分支 ($CURRENT_BRANCH) 拉取最新代码"
    echo "  [2] 切换到指定分支/标签"
    echo "  [3] 跳过代码更新"
    read -p "请选择 (默认: 1): " UPDATE_CHOICE
    UPDATE_CHOICE=${UPDATE_CHOICE:-1}

    case $UPDATE_CHOICE in
        1)
            # 拉取最新代码
            log_step "从当前分支 $CURRENT_BRANCH 拉取最新代码..."
            
            # 检查本地变更
            if [ -n "$(git status --porcelain)" ]; then
                log_warn "本地有未提交的变更，这些变更将被覆盖"
                git status --porcelain
                read -p "是否继续? (y/n, 默认: n): " CONTINUE_WITH_CHANGES
                if [ "${CONTINUE_WITH_CHANGES,,}" != "y" ]; then
                    log_error "部署已取消"
                    exit 1
                fi
            fi
            
            # 保存最新提交前的版本
            OLD_COMMIT=$(git rev-parse HEAD)
            
            # 获取远程变更
            git fetch --all
            
            # 检查是否有新的提交
            NEW_COMMIT=$(git rev-parse origin/$CURRENT_BRANCH)
            if [ "$OLD_COMMIT" = "$NEW_COMMIT" ]; then
                log_info "已经是最新版本，无需更新代码"
            else
                # 显示即将应用的变更摘要
                log_info "即将应用以下变更:"
                git log --oneline --no-decorate $OLD_COMMIT..$NEW_COMMIT
                
                # 应用变更
                git reset --hard origin/"$CURRENT_BRANCH"
                git pull
                log_info "代码已更新到最新版本"
            fi
            ;;
        2)
            # 切换到指定分支/标签
            echo ""
            echo "可用的分支:"
            git branch -r | grep -v HEAD | sed 's/origin\//  /'
            echo ""
            echo "可用的标签:"
            git tag | sed 's/^/  /'
            echo ""
            read -p "输入要切换到的分支或标签名: " TARGET_BRANCH
            
            if [ -z "$TARGET_BRANCH" ]; then
                log_error "未提供有效的分支或标签名，部署已取消"
                exit 1
            fi
            
            log_step "切换到 $TARGET_BRANCH..."
            git fetch --all --tags
            
            # 检查分支/标签是否存在
            if git rev-parse --verify --quiet origin/"$TARGET_BRANCH" >/dev/null; then
                # 分支存在
                git checkout "$TARGET_BRANCH"
                git reset --hard origin/"$TARGET_BRANCH"
            elif git rev-parse --verify --quiet "$TARGET_BRANCH" >/dev/null; then
                # 标签存在
                git checkout "$TARGET_BRANCH"
            else
                log_error "分支或标签 '$TARGET_BRANCH' 不存在，部署已取消"
                exit 1
            fi
            ;;
        3)
            log_info "跳过代码更新"
            ;;
        *)
            log_warn "无效选择，使用默认选项: 从当前分支拉取"
            git fetch --all
            git reset --hard origin/"$CURRENT_BRANCH"
            git pull
            ;;
    esac
fi

# 获取部署后的Git版本
NEW_VERSION=$(git describe --always --tags 2>/dev/null || echo 'Unknown')
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
    log_info "版本已更新: $OLD_VERSION → $NEW_VERSION"
fi

# 激活虚拟环境
log_step "更新Python环境..."
source venv/bin/activate || {
    log_error "无法激活虚拟环境！"
    exit 1
}

# 安装/更新依赖
log_info "更新Python依赖..."
pip install --upgrade pip
pip install -r requirements.txt
pip install gunicorn gevent

# 检查远程数据库配置
log_step "检查数据库配置..."
ENV_FILE="${APP_DIR}/.env"
if [ -f "$ENV_FILE" ]; then
    # 备份环境变量文件
    cp "$ENV_FILE" "${ENV_FILE}.bak"
    
    # 确保数据库配置存在
    DB_CONFIG_UPDATED=false
    
    if ! grep -q "DB_HOST=" "$ENV_FILE" || ! grep -q "DB_NAME=" "$ENV_FILE"; then
        log_warn "数据库配置缺失或不完整，更新远程数据库配置..."
        
        # 保留原有环境变量内容
        ENV_CONTENT=$(cat "$ENV_FILE")
        
        # 更新数据库配置
        cat > "$ENV_FILE" << EOF
# 远程数据库配置
DB_HOST=106.15.51.42
DB_PORT=3306
DB_NAME=csss
DB_USER=csss
DB_PASSWORD=12345

$ENV_CONTENT
EOF
        DB_CONFIG_UPDATED=true
    else
        # 检查并更新数据库连接信息
        if ! grep -q "DB_HOST=106.15.51.42" "$ENV_FILE"; then
            sed -i 's/DB_HOST=.*/DB_HOST=106.15.51.42/g' "$ENV_FILE"
            DB_CONFIG_UPDATED=true
        fi
        if ! grep -q "DB_PORT=3306" "$ENV_FILE"; then
            sed -i 's/DB_PORT=.*/DB_PORT=3306/g' "$ENV_FILE"
            DB_CONFIG_UPDATED=true
        fi
        if ! grep -q "DB_NAME=csss" "$ENV_FILE"; then
            sed -i 's/DB_NAME=.*/DB_NAME=csss/g' "$ENV_FILE"
            DB_CONFIG_UPDATED=true
        fi
        if ! grep -q "DB_USER=csss" "$ENV_FILE"; then
            sed -i 's/DB_USER=.*/DB_USER=csss/g' "$ENV_FILE"
            DB_CONFIG_UPDATED=true
        fi
        if ! grep -q "DB_PASSWORD=12345" "$ENV_FILE"; then
            sed -i 's/DB_PASSWORD=.*/DB_PASSWORD=12345/g' "$ENV_FILE"
            DB_CONFIG_UPDATED=true
        fi
    fi
    
    if [ "$DB_CONFIG_UPDATED" = true ]; then
        log_info "数据库配置已更新"
    else
        log_info "数据库配置正确，无需修改"
    fi
else
    log_warn "环境变量文件不存在，创建新的.env文件..."
    cat > "$ENV_FILE" << EOF
# 远程数据库配置
DB_HOST=106.15.51.42
DB_PORT=3306
DB_NAME=csss
DB_USER=csss
DB_PASSWORD=12345

# 应用配置
SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9!@#$%^&*(-_=+)' | head -c 50 || echo "django-insecure-default-key-please-change")
DEBUG=False
ALLOWED_HOSTS=*,localhost,127.0.0.1
EOF
    log_info "环境变量文件已创建"
fi

# 检查Gunicorn配置
log_step "检查Gunicorn配置..."
GUNICORN_CONFIG="${APP_DIR}/gunicorn_config.py"
if [ -f "$GUNICORN_CONFIG" ]; then
    # 检查绑定地址
    if grep -q "bind = \"127.0.0.1:8000\"" "$GUNICORN_CONFIG"; then
        log_warn "Gunicorn绑定地址限制为127.0.0.1，更新为0.0.0.0..."
        sed -i 's/bind = "127.0.0.1:8000"/bind = "0.0.0.0:8000"/g' "$GUNICORN_CONFIG"
        log_info "Gunicorn配置已更新"
    elif ! grep -q "bind = \"0.0.0.0:8000\"" "$GUNICORN_CONFIG"; then
        log_warn "未找到Gunicorn绑定配置，可能使用自定义配置"
    else
        log_info "Gunicorn配置正确，绑定到0.0.0.0:8000"
    fi
else
    log_warn "Gunicorn配置文件不存在，创建新配置..."
    cat > "$GUNICORN_CONFIG" << 'EOF'
# Gunicorn配置文件 - 妙趣拾光锦盒用户系统
import multiprocessing
import os

# 绑定地址和端口 - 绑定到所有接口，允许从任何IP访问
bind = "0.0.0.0:8000"

# 工作进程数量 - 2倍CPU核心数+1
workers = (multiprocessing.cpu_count() * 2) + 1
if workers > 12:  # 设置上限
    workers = 12

# 工作线程数量
threads = 2

# 工作模式 - 使用gevent异步处理请求
worker_class = "gevent"

# 请求超时时间(秒)
timeout = 120

# 优雅重启超时(秒)
graceful_timeout = 30

# 最大请求数，超过此数量后worker会重启
max_requests = 1000
max_requests_jitter = 100

# 日志配置
errorlog = os.path.join("/var/log/box-user", "gunicorn-error.log")
accesslog = os.path.join("/var/log/box-user", "gunicorn-access.log")
loglevel = "info"

# 守护进程模式 (在supervisor下不应设置为True)
daemon = False

# 进程名称
proc_name = "box-user"

# 优雅地关闭worker
preload_app = True
EOF

    log_info "Gunicorn配置文件已创建"
fi

# 检查启动脚本
log_step "检查启动脚本..."
START_SCRIPT="${APP_DIR}/start.sh"
if [ -f "$START_SCRIPT" ]; then
    # 检查是否使用了设置文件
    if ! grep -q "settings_production" "$START_SCRIPT"; then
        log_warn "启动脚本未使用生产设置，更新启动脚本..."
        cat > "$START_SCRIPT" << 'EOF'
#!/bin/bash
cd /var/www/box-user
source venv/bin/activate
export DJANGO_SETTINGS_MODULE=boxuser.settings_production
exec gunicorn --config=gunicorn_config.py boxuser.wsgi:application
EOF
        chmod +x "$START_SCRIPT"
        log_info "启动脚本已更新"
    else
        log_info "启动脚本配置正确"
    fi
else
    log_warn "启动脚本不存在，创建新脚本..."
    cat > "$START_SCRIPT" << 'EOF'
#!/bin/bash
cd /var/www/box-user
source venv/bin/activate
export DJANGO_SETTINGS_MODULE=boxuser.settings_production
exec gunicorn --config=gunicorn_config.py boxuser.wsgi:application
EOF
    chmod +x "$START_SCRIPT"
    log_info "启动脚本已创建"
fi

# 执行数据库迁移
log_step "执行数据库迁移..."
export DJANGO_SETTINGS_MODULE=boxuser.settings
python manage.py makemigrations
python manage.py migrate

# 收集静态文件
log_step "收集静态文件..."
python manage.py collectstatic --noinput

# 确保日志目录存在
log_step "检查日志目录..."
mkdir -p "${APP_DIR}/logs"
mkdir -p "/var/log/box-user"
chmod -R 755 "${APP_DIR}/logs"
chmod -R 755 "/var/log/box-user"

# 重启应用
log_step "重启应用服务..."
supervisorctl restart box-user

# 验证服务状态
log_step "验证服务状态..."
sleep 5 # 等待服务启动
supervisor_status=$(supervisorctl status box-user)
echo "$supervisor_status"

if echo "$supervisor_status" | grep -q "RUNNING"; then
    # 运行健康检查
    log_info "服务已成功重启，运行健康检查..."
    
    # 使用健康检查脚本（如果存在）
    if [ -f "${APP_DIR}/scripts/check_health.py" ]; then
        python "${APP_DIR}/scripts/check_health.py"
        HEALTH_CHECK_RESULT=$?
        
        if [ $HEALTH_CHECK_RESULT -eq 0 ]; then
            log_info "应用健康检查通过!"
        else
            log_warn "应用健康检查失败，可能存在问题"
            
            # 提示是否回滚
            read -p "是否回滚到之前的版本? (y/n, 默认: n): " ROLLBACK
            if [ "${ROLLBACK,,}" = "y" ]; then
                log_step "正在回滚到之前的版本..."
                # 停止服务
                supervisorctl stop box-user
                
                # 复制备份回来
                rsync -a "$BACKUP_DIR/" "$APP_DIR/"
                
                # 重启服务
                supervisorctl start box-user
                log_info "已回滚到之前的版本"
            fi
        fi
    else
        # 手动检查应用响应
        CURL_RESULT=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/ || echo "连接失败")
        
        if [ "$CURL_RESULT" = "200" ] || [ "$CURL_RESULT" = "302" ]; then
            log_info "应用验证成功! HTTP状态码: $CURL_RESULT"
        else
            log_warn "应用可能未正常运行，HTTP状态码: $CURL_RESULT"
            log_info "正在查看应用日志..."
            tail -n 50 /var/log/box-user/supervisor.err.log
            
            # 提示是否回滚
            read -p "是否回滚到之前的版本? (y/n, 默认: n): " ROLLBACK
            if [ "${ROLLBACK,,}" = "y" ]; then
                log_step "正在回滚到之前的版本..."
                # 停止服务
                supervisorctl stop box-user
                
                # 复制备份回来
                rsync -a "$BACKUP_DIR/" "$APP_DIR/"
                
                # 重启服务
                supervisorctl start box-user
                log_info "已回滚到之前的版本"
            fi
        fi
    fi
else
    log_error "服务启动失败！"
    log_info "正在查看应用日志..."
    tail -n 50 /var/log/box-user/supervisor.err.log
    
    log_step "自动执行回滚..."
    # 停止服务
    supervisorctl stop box-user
    
    # 复制备份回来
    rsync -a "$BACKUP_DIR/" "$APP_DIR/"
    
    # 重启服务
    supervisorctl start box-user
    log_warn "已自动回滚到之前的版本。"
fi

# 清理旧备份（保留最近10个备份）
log_step "管理备份文件..."
BACKUP_COUNT=$(find /var/backups/box-user -maxdepth 1 -type d | wc -l)
if [ $BACKUP_COUNT -gt 11 ]; then  # 11因为包括父目录
    log_info "清理旧备份，只保留最近10个备份..."
    ls -dt /var/backups/box-user/20* | tail -n +11 | xargs rm -rf
    log_info "旧备份清理完成"
fi

log_step "部署过程完成!"
log_info "部署日志保存在: $LOG_FILE"

# 显示Nginx和服务状态
echo ""
log_info "============= 部署摘要 ============="
log_info "部署时间: $(date)"
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
    log_info "代码版本: $OLD_VERSION → $NEW_VERSION"
else
    log_info "代码版本: $NEW_VERSION (未变更)"
fi
log_info "应用状态: $(supervisorctl status box-user | awk '{print $2}')"
nginx_status=$(systemctl status nginx | grep "Active:")
log_info "Nginx状态: $nginx_status"
log_info "=====================================" 